from django.test import TestCase, Client
from ..users.models import User
from .models import Device, UserDeviceMap
import json

class UserDeviceMapTestCase(TestCase):
    def setUp(self):
        # 创建测试用户
        self.user1 = User.objects.create(
            user_id='1',
            username='user1',
            password='password123',
            role='admin',
            permission_level=1
        )
        self.user2 = User.objects.create(
            user_id='2',
            username='user2',
            password='password123',
            role='user',
            permission_level=0
        )
        self.user3 = User.objects.create(
            user_id='3',
            username='user3',
            password='password123',
            role='user',
            permission_level=2
        )

        self.device1 = Device.objects.create(
            device_id='1', 
            device_name='空调',
            device_type='空调',
            location='客厅',
            status='online'
        )

        self.device2 = Device.objects.create(
            device_id='2',
            device_name='加湿器',
            device_type='加湿器',
            location='卧室',
            status='offline'
        )

        self.device3 = Device.objects.create(
            device_id='3',
            device_name='加湿器',
            device_type='加湿器',
            location='卧室',
            status='offline'
        )
        
        # 创建初始映射
        self.mapping1 = UserDeviceMap.objects.create(
            user=self.user3,
            device=self.device3,
            permission='read'
        )
        # 初始化测试客户端
        self.client = Client()
    
    def test_create_mapping_success(self):
        """测试成功创建用户设备映射"""
        data = {
            'user_id': self.user1.user_id,  
            'device_id': self.device1.device_id,  
            'permission': 'write'
        }
        response = self.client.post(
            '/api/v1/user-device-map/create/',
            data=json.dumps(data),
            content_type='application/json'
        )
        self.assertEqual(response.status_code, 201)
        response_data = json.loads(response.content)
        self.assertEqual(response_data['code'], 0)
        self.assertEqual(response_data['message'], '创建成功')
        self.assertEqual(response_data['data']['user_id'], self.user1.user_id)  
        self.assertEqual(response_data['data']['device_id'], self.device1.device_id)
        self.assertEqual(response_data['data']['permission'], 'write')
        
        # 验证数据库中有新记录
        self.assertTrue(UserDeviceMap.objects.filter(
            user=self.user1,
            device=self.device1,
            permission='write'
        ).exists())
        
    
    def test_create_mapping_duplicate(self):
        #测试创建重复映射
        data = {
            'user_id': self.user1.user_id,
            'device_id': self.device1.device_id,  
            'permission': 'write'
        }

        response = self.client.post(
            '/api/v1/user-device-map/create/',
            data=json.dumps(data),
            content_type='application/json'
        )
        duplicate_data = {
            'user_id': self.user1.user_id,
            'device_id': self.device1.device_id,
            'permission': 'write'
        }
        response = self.client.post(
            '/api/v1/user-device-map/create/',
            data=json.dumps(duplicate_data),
            content_type='application/json'
        )

        
        self.assertEqual(response.status_code, 400)
        response_data = json.loads(response.content)
        self.assertEqual(response_data['code'], 1003)
        self.assertEqual(response_data['message'], '该映射已存在')
    
    def test_create_mapping_user_not_exist(self):
        #测试为不存在的用户创建映射
        data = {
            'user_id': 999,  # 不存在的用户ID
            'device_id': self.device1.device_id,
            'permission': 'read'
        }
        response = self.client.post(
            '/api/v1/user-device-map/create/',
            data=json.dumps(data),
            content_type='application/json'
        )
        
        self.assertEqual(response.status_code, 404)
        response_data = json.loads(response.content)
        self.assertEqual(response_data['code'], 1001)
        self.assertEqual(response_data['message'], '用户不存在')
        
    
    def test_create_mapping_device_not_exist(self):
        #测试为不存在的设备创建映射
        data = {
            'user_id': self.user1.user_id,
            'device_id': '999',  # 不存在的设备ID
            'permission': 'read'
        }
        response = self.client.post(
            '/api/v1/user-device-map/create/',
            data=json.dumps(data),
            content_type='application/json'
        )
        
        self.assertEqual(response.status_code, 404)
        try:
            response_data = json.loads(response.content)
            self.assertEqual(response_data['code'], 1002)
            self.assertEqual(response_data['message'], '设备不存在')
        except json.JSONDecodeError:
            self.fail("后端返回的内容不是有效的 JSON 格式")
    
    def test_list_mappings_all(self):
        #测试获取所有映射
        # 先创建第二条映射


        UserDeviceMap.objects.create(
            user_id=self.user2.user_id,
            device_id=self.device2.device_id,
            permission='admin'
        )
        
        response = self.client.get('/api/v1/user-device-map/')
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content)
        
        self.assertEqual(response_data['code'], 0)
        self.assertEqual(response_data['message'], '查询成功')
        self.assertEqual(response_data['data']['total'], 2)
        self.assertEqual(len(response_data['data']['mappings']), 2)
    
    def test_list_mappings_filter_by_user(self):
        #测试按用户ID过滤映射
        response = self.client.get(f'/api/v1/user-device-map/?user_id={self.user3.user_id}')
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content)
        
        self.assertEqual(response_data['code'], 0)
        self.assertEqual(response_data['data']['total'], 1)
        self.assertEqual(response_data['data']['mappings'][0]['user_id'], self.user3.user_id)
        self.assertEqual(response_data['data']['mappings'][0]['device_id'], self.device3.device_id)
    
    def test_list_mappings_filter_by_device(self):
        #测试按设备ID过滤映射
        response = self.client.get(f'/api/v1/user-device-map/?device_id={self.device3.device_id}')
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content)
        
        self.assertEqual(response_data['code'], 0)
        self.assertEqual(response_data['data']['total'], 1)
        self.assertEqual(response_data['data']['mappings'][0]['device_id'], self.device3.device_id)
        self.assertEqual(response_data['data']['mappings'][0]['user_id'], self.user3.user_id)
    
    def test_retrieve_mapping_success(self):
        #测试获取单个映射
        response = self.client.get(f'/api/v1/user-device-map/{self.user3.user_id}/{self.device3.device_id}/')
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content)
        
        self.assertEqual(response_data['code'], 0)
        self.assertEqual(response_data['message'], '查询单条成功')
        self.assertEqual(response_data['data']['user_id'], self.user3.user_id)
        self.assertEqual(response_data['data']['device_id'], self.device3.device_id)
        self.assertEqual(response_data['data']['permission'], 'read')
    
    def test_retrieve_mapping_not_found(self):
        #测试获取不存在的映射
        response = self.client.get(f'/api/v1/user-device-map/999/{self.device1.device_id}/')
        self.assertEqual(response.status_code, 404)
    
    def test_update_mapping_success(self):
        #测试更新映射权限
        data = {'permission': 'admin'}
        response = self.client.put(
            f'/api/v1/user-device-map/{self.user3.user_id}/{self.device3.device_id}/update/',
            data=json.dumps(data),
            content_type='application/json'
        )
        
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content)
        self.assertEqual(response_data['code'], 0)
        self.assertEqual(response_data['message'], '更新成功')
        self.assertEqual(response_data['data']['permission'], 'admin')
        
        # 验证数据库已更新
        mapping = UserDeviceMap.objects.get(user=self.user3, device=self.device3)
        self.assertEqual(mapping.permission, 'admin')
    
    def test_update_mapping_not_found(self):
        #测试更新不存在的映射
        data = {'permission': 'admin'}
        response = self.client.put(
            f'/api/v1/user-device-map/999/{self.device3.device_id}/update/',
            data=json.dumps(data),
            content_type='application/json'
        )
        
        self.assertEqual(response.status_code, 404)
    
    def test_delete_mapping_success(self):
        #测试删除映射
        response = self.client.delete(
            f'/api/v1/user-device-map/{self.user3.user_id}/{self.device3.device_id}/delete/'
        )
        
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content)
        self.assertEqual(response_data['code'], 0)
        self.assertEqual(response_data['message'], '删除成功')
        
        # 验证数据库已删除
        self.assertFalse(UserDeviceMap.objects.filter(
            user=self.user3,
            device=self.device3
        ).exists())
    
    def test_delete_mapping_not_found(self):
        #测试删除不存在的映射
        response = self.client.delete(
            f'/api/v1/user-device-map/999/{self.device3.device_id}/delete/'
        )
        
        self.assertEqual(response.status_code, 404)
    
    def test_invalid_methods(self):
        #测试不支持的HTTP方法
        # POST 不允许的路径
        response = self.client.post('/api/v1/user-device-map/1/1/')
        self.assertEqual(response.status_code, 405)
        
        # PUT 不允许的路径
        response = self.client.put('/api/v1/user-device-map/')
        self.assertEqual(response.status_code, 405)
        
        # DELETE 不允许的路径
        response = self.client.delete('/api/v1/user-device-map/')
        self.assertEqual(response.status_code, 405)